<?php

namespace App\Task;

use App\Model\Live;
use App\Model\Play;
use App\Utils\Enum\ImEnum;
use App\Utils\Enum\LiveEnum;
use App\Utils\Enum\MatchEnum;
use App\Utils\Im;
use App\Websocket\ImWebsocket;
use Exception;
use Hyperf\Redis\Redis;
use Hyperf\WebSocketServer\Sender;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use RedisException;

class VirtualAnchorLiveTask extends AbstractBaseTask
{
    public function execute(): void
    {
        $succ = 0;
        //比赛结束的虚拟直播间关播
        $res = Live::query()->where([['status', '=', LiveEnum::STATUS_LIVING], ['is_virtual', '=', 1], ['match_status', '<>', MatchEnum::MATCH_STATUS_ING]])->get();
        if ($res) {
            foreach ($res as $r) {
                Live::query()->where('id', $r['id'])->update(['match_id' => '', 'match_time' => 0, 'match_status' => 0, 'status' => LiveEnum::STATUS_CLOSED]);
                $this->_pushMessage($r['room_id']);
            }
        }
        //获取全部没有直播的比赛
        $matchIds = Play::query()->where([['match_status', '=', MatchEnum::MATCH_STATUS_ING], ['video_url', '<>', '']])->select(['match_id'])->pluck('match_id')->toArray();
        if (!empty($matchIds)) {
            $liveMatchIds = Live::query()->whereIn('match_id', $matchIds)->get(['match_id'])->pluck('match_id')->toArray();
            $notLiveMatchIds = array_diff($matchIds, $liveMatchIds);
            if (!empty($notLiveMatchIds)) {
                $matchList = Play::query()->whereIn('match_id', $notLiveMatchIds)->orderBy('match_time', 'asc')->get()->toArray();
                //获取全部空闲虚拟直播间
                $liveRoomList = Live::query()->where(['is_virtual' => 1, 'status' => LiveEnum::STATUS_CLOSED])->orderByRaw('rand()')->get();
                if (!empty($liveRoomList)) {
                    foreach ($liveRoomList as $i => $live) {
                        if (!isset($matchList[$i])) {
                            continue;
                        }
                        $match = &$matchList[$i];
                        $update = [
                            'match_id' => $match['match_id'],
                            'match_time' => $match['match_time'],
                            'match_status' => $match['match_status'],
                            'room_name' => sprintf('%s VS %s', $match['home_team_name'], $match['away_team_name']),
                            'play_stream_address2' => $match['video_url'],
                            'status' => LiveEnum::STATUS_LIVING,
                        ];
                        Live::query()->where('id', $live['id'])->update($update);
                        $succ++;
                    }
                }
            }
        }
        $this->logger->warning(sprintf('%d 个虚拟直播间已经开播.', $succ));
    }



    /**
     * 下发下播消息
     * @param $roomId
     * @return void
     */
    private function _pushMessage($roomId): void
    {
        try {
            $redis = $this->container->get(Redis::class);
            $fds = $redis->sMembers(ImWebsocket::KeyGroup($roomId));
            if (!empty($fds)) {
                $sender = $this->container->get(Sender::class);
                $msg = Im::Create('ImDoResult', ['code' => ImEnum::IM_DO_LIVE_OFF, 'data' => new_json_encode(['roomId' => $roomId, 'status' => LiveEnum::STATUS_CLOSED])]);
                foreach ($fds as $fd) {
                    $fd = (int)$fd;
                    try {
                        if ($sender->check($fd)) {
                            $sender->push($fd, $msg, WEBSOCKET_OPCODE_BINARY);
                        }
                    } catch (Exception $e) {
                        $this->logger->error(sprintf('推送下播消息失败 fd=%d error=%s', $fd, $e->getMessage()));
                    }
                }
            }
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface|RedisException $e) {
            $this->logger->error(sprintf('推送下播消息失败 error=%s', $e->getMessage()));
        }
    }
}